﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// This filter might be used to compare two same size pictures.
    /// If a pixel in the first pic produces the same value as a pixel
    /// in the second pic, the pixel is set to white, else it blacked out.
    /// </summary>
    public class SameColorValues : BaseForeBackgroundColorFilter, ITwoSourceFilter
    {
        protected bool m_bSameValues = true;
        protected int m_nTolerance = 70;

        /// <summary>
        /// Initializes a new instance of the <see cref="SameColorValues"/> class.
        /// </summary>
        public SameColorValues()
            : this(true)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SameColorValues"/> class.
        /// </summary>
        /// <param name="_bSameValues">if set to <c>true</c> [_b same values].</param>
        public SameColorValues(bool _bSameValues)
        {
            m_bSameValues = _bSameValues;
            M_PROCESSING_MODE = PROCESSING_MODE.GrayValue;
        }

        /// <summary>
        /// Gets or sets tolerance
        /// </summary>
        public int Tolerance
        {
            get { return m_nTolerance; }
            set { m_nTolerance = value; }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SameColorValues"/> class.
        /// </summary>
        /// <param name="_processingMode">The _processing mode.</param>
        public SameColorValues(PROCESSING_MODE _processingMode, bool _bSameValues)
            : this(_bSameValues)
        {
            M_PROCESSING_MODE = _processingMode;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SameColorValues"/> class.
        /// </summary>
        /// <param name="_sameColorValues">The _same color values.</param>
        internal SameColorValues(SameColorValues _sameColorValues)
        {
            this.M_PROCESSING_MODE = _sameColorValues.M_PROCESSING_MODE;
        }

        /// <summary>
        /// Gets or sets a value indicating whether [same values].
        /// </summary>
        /// <value><c>true</c> if [same values]; otherwise, <c>false</c>.</value>
        public bool SameValues
        {
            get { return m_bSameValues; }
            set { m_bSameValues = value; }
        }

        /// <summary>
        /// Execute this Filter
        /// A Debug Statement is written if a concrete Filter is called
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            Process((UnsafeBitmap)_bitmap.Clone(), _bitmap);
            return _bitmap;
        }

        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new SameColorValues(this);
        }

        #region ITwoSourceFilter Members

        /// <summary>
        /// Processes the specified _bitmap source.
        /// </summary>
        /// <param name="_bitmapSource">The _bitmap source.</param>
        /// <param name="_bitmapDest">The _bitmap dest.</param>
        public UnsafeBitmap Process(UnsafeBitmap _bitmapSource, UnsafeBitmap _bitmapDest)
        {
            UnsafeBitmap bitmapSource = _bitmapSource;
            UnsafeBitmap bitmapDest = _bitmapDest;

            int nHeight = bitmapSource.Height;
            int nWidth = bitmapSource.Width;

            ColorCalculation calculation = Definitions.ColorCalculationDictionaryProcessingMode[M_PROCESSING_MODE];

            int x = 0;
            int y = 0;

            bool bValue = false;
            for (y = 0; y < nHeight; y++)
            {
                for (x = 0; x < nWidth; x++)
                {
                    if (m_nTolerance > 0)
                    {
                        //use tolerance
                        bValue = Math.Abs(calculation(bitmapSource.GetPixel(x, y)) - calculation(bitmapDest.GetPixel(x, y))) < m_nTolerance;
                    }
                    else
                    {
                        //old behaviour, to be compatible
                        bValue = calculation(bitmapSource.GetPixel(x, y)) == calculation(bitmapDest.GetPixel(x, y));
                    }
                    if (m_bSameValues)
                    {
                        bitmapDest.SetPixel(x, y, bValue ? m_ColorForeground : m_ColorBackground);
                    }
                    else
                    {
                        bitmapDest.SetPixel(x, y, !bValue ? m_ColorForeground : m_ColorBackground);
                    }
                }
            }
            bitmapSource.Dispose();
            bitmapDest.Dispose();
            return bitmapDest;
        }

        #endregion
    }
}
